define(['text!html/search.html', 'text!html/searchResults.html', 'text!html/searchHistory.html', 'css!styles/search.css', 'js/navigationManager', 'js/authenticationPresenter', 'js/bookingsPresenter', 'js/serverWrapper', 'js/dbWrapper', 'knockoutjs'], function (searchTemplate, searchResultsTemplate, searchHistoryTemplate, _style, navigationManager, authenticationPresenter, bookingsPresenter, serverWrapper, dbWrapper, ko) {
    return new function () {
        var presenter = this;
        var destinationsPromise = serverWrapper.getAllDestinations();
        var lastSearch = new searchViewModel();

        function searchViewModel() {
            var self = this;

            self.source = ko.observable();
            self.destination = ko.observable();
            self.departure = ko.observable();
            self.maxCost = ko.observable();
            self.failed = ko.observable(false);
            self.destinations = ko.observableArray();

            $.when(destinationsPromise).then(function (desinations) {
                if (!desinations) return;
                for (var i = 0; i < desinations.length; ++i) {
                    self.destinations.push(desinations[i]);
                }
            });

            self.search = function () {
                var onFailure = function () {
                    self.failed(true);
                };

                serverWrapper
                    .search(self.source(), self.destination(), self.departure(), self.maxCost())
                    .success(function (result) {
                        if (!result || result.length == 0) return onFailure();
                        dbWrapper.saveSearch(self.source(), self.destination(), self.departure(), self.maxCost());
                        navigationManager.load('searchResults', searchResultsTemplate, new resultsViewModel(result));
                    })
                    .error(onFailure);
            };

            self.history = function () {
                navigationManager.load('searchHistory', searchHistoryTemplate, new historyViewModel());
            };
        };

        function historyViewModel() {
            var self = this;

            self.results = ko.observableArray();

            dbWrapper.getSearches(function (results) {
                results.forEach(function (item) {
                    item.click = function () {
                        lastSearch.source(item.source);
                        lastSearch.destination(item.destination);
                        lastSearch.departure(item.departure);
                        lastSearch.maxCost(item.maxCost);
                        presenter.bind();
                    };
                    self.results.push(item);
                });
            });
        };

        function resultsViewModel(results) {

            this.results = ko.observableArray();
            for (var i = 0; i < results.length; ++i) {
                var itemModel = new resultViewModel(results[i]);
                itemModel.emptyFlight.add(function (model) {
                    var index = this.results().indexOf(model);
                    this.results.splice(index, 1);
                });

                this.results.push(itemModel);
            }
        };

        function resultViewModel(result) {
            var self = this;

            self.emptyFlight = $.Callbacks();
            self.flightId = ko.observable(result.flight_id);
            self.airline = ko.observable(result.airline_name);
            self.flightNumber = ko.observable(result.flight_number);
            self.departAirport = ko.observable(result.depart_airport);
            self.arrivalAirport = ko.observable(result.arrival_airport);
            self.departDate = ko.observable(result.depart_date);
            self.isExpanded = ko.observable(false);
            self.classes = ko.observableArray();

            var initSeats = function (seats) {
                if (!seats) return;

                var classes = self.classes();
                for (var i = 0; i < seats.length; ++i) {
                    if (seats[i].is_reserved) continue;
                    var isFound = false;
                    if (i < seats.length) {
                        for (var j = 0; j < classes.length; ++j) {
                            if (classes[j].name() == seats[i].seat_class) {
                                classes[j].seats(classes[j].seats() + 1);
                                isFound = true;
                                break;
                            }
                        }
                    }

                    if (!isFound) self.classes.push(new classViewModel(seats[i], self));
                }

                if (self.classes().length == 0) {
                    self.emptyFlight.fire(self);
                }
            };

            serverWrapper
                .getSeatsForFlight(result.flight_id)
                .success(initSeats);

            self.flightClick = function () {
                self.isExpanded(!self.isExpanded());
            };
        };

        function classViewModel(seat, flight) {
            var self = this;

            self.name = ko.observable(seat.seat_class);
            self.seats = ko.observable(1);
            self.price = ko.observable(seat.cost);
            self.flightId = ko.observable(flight.flightId());
            self.departAirport = ko.observable(flight.departAirport());
            self.arrivalAirport = ko.observable(flight.arrivalAirport());
            self.departDate = ko.observable(flight.departDate());
            self.airline = ko.observable(flight.airline());
            self.book = function () {
                if (authenticationPresenter.loggedInUserType != 'member') {
                    authenticationPresenter.authenticate(self.book);
                } else {
                    bookingsPresenter.book(self);
                }
            };
        };

        presenter.bind = function () {
            navigationManager.load('search', searchTemplate, lastSearch);
        };
    };
});